package com.gbase8c.dmt.db.oracle;

import com.gbase8c.dmt.common.exception.MetadataException;
import com.gbase8c.dmt.db.object.IndexObject;
import com.gbase8c.dmt.db.object.TableObject;
import com.gbase8c.dmt.model.migration.dto.DataSourceDto;
import com.gbase8c.dmt.model.migration.dto.PartitionInfoDto;
import com.gbase8c.dmt.model.migration.dto.TableDto;
import com.gbase8c.dmt.model.migration.dto.TableTypeMapperDto;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.dbutils.*;
import org.apache.commons.dbutils.handlers.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public class TableObjectImpl extends MetaImpl implements TableObject {

    protected IndexObject indexObject;
    private static Integer defaultPrecision = 38;

    public TableObjectImpl(DataSourceDto dataSourceDto) {
        super(dataSourceDto);
        indexObject = new IndexObjectImpl(dataSourceDto);
    }

    protected final Logger logger  = LoggerFactory.getLogger(this.getClass());

    @Override
    public List<String> getNames(Map<String, Object> params) {
        String schema = (String) params.get("schema");
        String sql = "SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = ?";
        List<String> tableNames = query(sql, new ColumnListHandler<String>(), schema);
        return tableNames;
    }

//    public List<TableTypeConfig.TableTypeMapper> getTableTypeMapper(Map<String,>){
//
//    }

    @Override
    public TableDto get(String name, Map<String, Object> params) {
//        String oracleSchema = schema.toUpperCase();
//        String oracleTable = tableName.toUpperCase();
        String schema = (String) params.get("schema");
        List<String> tableSpaceNames = (List<String>) params.get("tableSpaceNames");

        String sql = "select owner as schema, table_name, column_name as name, data_type, data_length, data_precision, data_scale, nullable from all_tab_columns where owner = ? and table_name = ? order by column_id asc";

        String pkSql = "SELECT A.COLUMN_NAME FROM ALL_CONS_COLUMNS A,ALL_CONSTRAINTS B WHERE A.constraint_name = B.constraint_name AND  B.constraint_type = 'P'" +
                "AND A.OWNER = ? AND A.table_name = ?";

        String isPartSql = "SELECT PARTITIONED FROM ALL_TABLES WHERE owner = ? and TABLE_NAME = ?";

        String tableSpaceSql = "select tablespace_name as tableSpaceName from dba_tables where owner = ? and table_name = ? and tablespace_name not in ('EXAMPLE','INDX','ODM','TOOLS','USERS','XDB','SYSTEM','UNDOTBS1','TEMP','CWMLITE','DRSYS','SYSAUX')";

        String partSql = "select keys.column_name partitioncolumn,parttables.partitioning_type partitionby,dba_tables.partitioned \n" +
                "from dba_part_key_columns keys ,dba_part_tables parttables,dba_tables where keys.name = parttables.table_name and " +
                "dba_tables.table_name = keys.name and keys.owner = ? and keys.name = ?";

        String partColumnsSql = "select keys.column_name partitioncolumn " +
                "from dba_part_key_columns keys ,dba_part_tables parttables,dba_tables where keys.name = parttables.table_name and " +
                "dba_tables.table_name = keys.name and keys.owner = ? AND PARTTABLES.owner = ? AND dba_tables.owner = ? " +
                "and keys.name = ? ORDER BY column_position";

        String partitionBySql = "select parttables.partitioning_type partitionby " +
                "from dba_part_key_columns keys ,dba_part_tables parttables,dba_tables where keys.name = parttables.table_name and " +
                "dba_tables.table_name = keys.name and keys.owner = ? and keys.name = ?";

        String subPartSql = "select subkeys.owner,SUBKEYS.name," +
                "PARTTABLES.subpartitioning_TYPE as subpartition_type,SUBKEYS.COLUMN_NAME AS subcolumn_name,column_position from dba_part_tables parttables,dba_tables,dba_subpart_key_columns SUBKEYS \n" +
                "where subkeys.name = parttables.table_name and dba_tables.table_name = subkeys.name and subkeys.owner = ? and subkeys.name = ?";

        String subPartColumnsSql = "select SUBKEYS.COLUMN_NAME from dba_part_tables parttables,dba_tables,dba_subpart_key_columns SUBKEYS " +
                "where subkeys.name = parttables.table_name and dba_tables.table_name = subkeys.name " +
                "and subkeys.owner = ? AND PARTTABLES.owner = ? AND dba_tables.owner = ? and subkeys.name = ? ORDER BY column_position";

        String subPartitionBySql = "select \n" +
                "PARTTABLES.subpartitioning_TYPE as subpartition_type from dba_part_tables parttables,dba_tables,dba_subpart_key_columns SUBKEYS " +
                "where subkeys.name = parttables.table_name and dba_tables.table_name = subkeys.name and subkeys.owner = ? and subkeys.name = ?";

        //查询表占用大小
        String dataSizeSql = "select ROUND(SUM(BYTES)/(1024*1024),2) data_size from DBA_SEGMENTS\n" +
                "where INSTR(SEGMENT_TYPE,'TABLE') = 1 AND OWNER = ? and SEGMENT_NAME = ?";

        //查询表注释
        String tableCommentSql = "SELECT comments FROM dba_tab_comments where owner = ? AND table_name = ? AND table_type = 'TABLE'";

        //查询列注释
        String columnCommentSql = "SELECT comments FROM dba_col_comments where owner = ? AND table_name = ? AND column_name = ?";

        //查询列默认值
        String defaultSql = "select data_default from all_tab_columns where owner = ? and table_name = ? AND column_name = ?";

//        String selectFromDualSql = "select ? from dual";
        String selectFromUnixTimeSql = "select from_unixtime(?) ";

        TableDto tableDto = null;
        List<TableDto.ColumnDto> columnDtos = null;
        List<String> pkList = null;
        String tableSpace = null;
        BeanProcessor beanProcessor = new GenerousBeanProcessor();
        RowProcessor rowProcessor = new BasicRowProcessor(beanProcessor);
        columnDtos = query(sql, new BeanListHandler<>(TableDto.ColumnDto.class, rowProcessor), schema, name);

        BigDecimal dataSize = new BigDecimal(0.00);
        //查询表大小
        dataSize = query(dataSizeSql, new ScalarHandler<BigDecimal>(), schema, name);
        if (dataSize == null) {
//            logger.info("dastasize = 0");
            dataSize = new BigDecimal(0.00);
        }

        //查询表注释
        String tableComment = query(tableCommentSql, new ScalarHandler<>(), schema, name);

        //查询主键
        pkList = query(pkSql, new ColumnListHandler<String>(),schema, name);
//
        for (TableDto.ColumnDto columnDto : columnDtos) {
            columnDto.setSqlType(toSqlType(columnDto.getDataType()));
            if (Objects.equals(columnDto.getSqlType(),Types.NUMERIC)
                    && !(Objects.isNull(columnDto.getDataScale()))
                    && (Objects.isNull(columnDto.getDataPrecision()))
                    && columnDto.getDataScale() == 0){
                columnDto.setDataPrecision(defaultPrecision);
            }
            if (Objects.equals(columnDto.getSqlType(),Types.NUMERIC)
                    && !(Objects.isNull(columnDto.getDataScale()))
                    && !(Objects.isNull(columnDto.getDataPrecision()))
                    && columnDto.getDataScale() == 0){
                Integer dataPrecision = columnDto.getDataPrecision();
                if (dataPrecision>0 && dataPrecision<=4) {
                    columnDto.setSqlType(Types.SMALLINT);
                } else if (dataPrecision>4 && dataPrecision<=9){
                    columnDto.setSqlType(Types.INTEGER);
                } else if (dataPrecision>9 && dataPrecision<=18){
                    columnDto.setSqlType(Types.BIGINT);
                }
            }
//
//          TODO pk
//          主键
            if (pkList.contains(columnDto.getName())) {
                columnDto.setPk(true);
            }
//          查询列注释
            String columnComment = query(columnCommentSql,new ScalarHandler<>(),schema,name,columnDto.getName());
            columnDto.setColumnComment(columnComment);
            //查询列默认值
            String columnDefault = query(defaultSql,new ScalarHandler<>(),schema,name,columnDto.getName());
            if (null != columnDefault){
//                columnDto.setDataDefault(columnDefault.replaceAll("\'",""));
                if (columnDefault.equalsIgnoreCase("sysdate")) {
                    columnDefault = columnDefault;
                } else {
                    columnDefault = columnDefault;
                }
                columnDto.setDataDefault(columnDefault);
            }
        }

        Map<String,String> columnDto = columnDtos.stream()
                .collect(Collectors.toMap(TableDto.ColumnDto::getName, TableDto.ColumnDto::getDataType));

//        List<Map<String, Object>> partitionInfos = Lists.newArrayList();
        List<PartitionInfoDto> partitionInfos = Lists.newArrayList();

//        List<String> isPart = query(isPartSql, new ColumnListHandler<String>(), name);
        Map<String, Object> properties = new HashMap<>();

        String partInfoSql = "SELECT partition_name as partitionName, high_value as highValue FROM ALL_TAB_PARTITIONS " +
                "WHERE table_owner = ? AND table_name = ? order by partition_position";

        //查是否是分区表，如果是 查具体信息
        List<String> isPart = query(isPartSql, new ColumnListHandler<String>(), schema, name);
        if (isPart != null && !isPart.isEmpty() && "YES".equals(isPart.get(0))){
//            properties = query(partSql, new MapHandler(), schema, name);
            List<String> partColumns = query(partColumnsSql,new ColumnListHandler<>(),schema,schema,schema,name);
            String partitionBy = query(partitionBySql,new ScalarHandler<>(),schema,name);
            properties.put("PARTITIONCOLUMN",StringUtils.join(partColumns,","));
            properties.put("PARTITIONBY",partitionBy);
            List<String> subPartColumns = query(subPartColumnsSql,new ColumnListHandler<>(),schema,schema,schema,name);
            String subPartitionBy = query(subPartitionBySql,new ScalarHandler<>(),schema,name);
            Map<String, Object> subPartProperties = new HashMap<>();
            if (null != subPartitionBy) {
                properties.put("SUBPARTITION_TYPE",subPartitionBy);
                properties.put("SUBCOLUMN_NAME",StringUtils.join(subPartColumns,","));
                subPartProperties.put("SUBPARTITION_TYPE",subPartitionBy);
                subPartProperties.put("SUBCOLUMN_NAME",StringUtils.join(subPartColumns,","));
            }
            partitionInfos = processPartition(schema,name,partInfoSql,partitionInfos,columnDto,properties,subPartProperties);
            properties.put("PARTITIONED","YES");
        } else {
            properties = new HashMap<>();
            properties.put("PARTITIONED","NO");
        }

        List<String> tableSpaceName = query(tableSpaceSql,new ColumnListHandler<String>(), schema,name);
        if(tableSpaceName != null && !tableSpaceName.isEmpty() && tableSpaceNames.containsAll(tableSpaceName)){
            tableSpace = tableSpaceName.get(0);
            properties.put("ISTOTABLESPACE","YES");
        } else{
            properties.put("ISTOTABLESPACE","NO");
        }

        //插入索引
//            List<IndexDto> indexDtos = indexObject.getIndexDtos(schema, name, tableSpaceNames);
        properties.put("DISTRIBUTETYPE","DISTRIBUTION");
        properties.put("DISTRIBUTEBY","HASH");
        properties.put("DISTRIBUTECOLUMN",columnDtos.get(0).getName());

        tableDto = TableDto.builder()
                .ds(dataSourceDto.getId())
                .tableSpaceName(tableSpace)
                .schema(schema)
                .name(name)
                .columnDtos(columnDtos)
                .dataSize(dataSize.doubleValue())
                .tableComment(tableComment)
                .properties(properties)
                .partitionInfos(partitionInfos)
                .build();

        return tableDto;
    }

    @Override
    public TableDto convert(TableDto tableDto, Map<String, Object> params) {
        return null;
    }

    @Override
    public String sql(TableDto tableDto, Map<String, Object> params) {
        return null;
    }

    @Override
    public List<String> tableSql(TableDto tableDto) {
        List<String> sqls = Lists.newArrayList();
        String sql = "select count(*) from all_tables where owner = ? and table_name = ?";
        QueryRunner qr = new QueryRunner(dataSource());
        try {
            Number number = qr.query(sql, new ScalarHandler<Number>(), tableDto.getSchema().toUpperCase(), tableDto.getName().toUpperCase());
            Long count = number.longValue();
            if (count > 0) {
                sqls.add("DROP TABLE " + tableDto.getSchema() + "."+ tableDto.getName());
            }
        } catch (Exception e) {
            log.error("查询表是否存在出错!", e);
            throw MetadataException.asMetadataException("查询表是否存在出错!", e);
        }
        boolean preserveCase = tableDto.getTask().getMigrateConfig().isPreserveCase();
        StringBuilder sb = new StringBuilder();
        sb.append("CREATE TABLE ")
                .append(wrap(tableDto.getSchema(), preserveCase))
                .append(".")
                .append(wrap(tableDto.getName(), preserveCase))
                .append(" (").append("\r\n");
        List<TableDto.ColumnDto> columnDtos = tableDto.getColumnDtos();

        // TODO 可能考虑的不全
        for (int i=0; i<columnDtos.size(); i++) {
            TableDto.ColumnDto column = columnDtos.get(i);
            sb.append(wrap(column.getName(), preserveCase))
                    .append(" ");
            String dataType = column.getTarDataType();
            sb.append(dataType);
            if (dataType.equalsIgnoreCase("NUMBER")
                    || dataType.equalsIgnoreCase("FLOAT")
                    || dataType.equalsIgnoreCase("BINARY_FLOAT")
                    || dataType.equalsIgnoreCase("BINARY_DOUBLE")) {
                Integer dataPrecision = column.getTarDataPrecision();
                Integer dataScale = column.getTarDataScale();
                if (dataPrecision != null) {
                    sb.append("(").append(dataPrecision);
                    if ( dataScale != null) {
                        sb.append(", ").append(dataScale);
                    }
                    sb.append(")");
                }
            } else {
                //Integer dataLength = column.getTarDataLength();
                if (column.getDataLength() != null) {
                    sb.append("(").append(column.getDataLength()).append(")");
                }
            }
            if (i < columnDtos.size() - 1) {
                sb.append(", \r\n");
            }
        }
        sb.append(")");
        sqls.add(sb.toString());
        return sqls;
    }

    @Override
    public List<TableTypeMapperDto> tableTypeMapper(String schema) {
        List<TableTypeMapperDto> resultList = new ArrayList<>();
        //获取schema下所有表主键sql
        String getSchemaAllTablePkSql = "select c.table_name, c.column_name\n" +
                "from DBA_CONS_COLUMNS c\n" +
                "         join DBA_CONSTRAINTS k\n" +
                "              on c.OWNER = k.OWNER\n" +
                "                  and c.CONSTRAINT_NAME = k.CONSTRAINT_NAME\n" +
                "                  and c.TABLE_NAME = k.TABLE_NAME\n" +
                "where k.CONSTRAINT_TYPE = 'P'\n" +
                "  and c.OWNER = ?";
        //获取schema下所有表外键sql
        String getSchemaAllTableFkSql = "select c.table_name, c.column_name\n" +
                "from DBA_CONS_COLUMNS c\n" +
                "         join DBA_CONSTRAINTS k\n" +
                "              on c.OWNER = k.OWNER\n" +
                "                  and c.CONSTRAINT_NAME = k.CONSTRAINT_NAME\n" +
                "                  and c.TABLE_NAME = k.TABLE_NAME\n" +
                "where k.CONSTRAINT_TYPE = 'R'\n" +
                "  and c.OWNER = ?";
        //获取schema下所有表第一列字段名sql
        String getSchemaAllTableFistColSql = "select t.table_name, c.column_name \n" +
                "from DBA_TAB_COLUMNS c,DBA_TABLES t\n" +
                "where c.COLUMN_ID = 1 and c.TABLE_NAME=t.TABLE_NAME\n" +
                "and  c.owner = ?";
        //获取schema下所有表
        String getSchemaAllTableDataSizeSql = "select SEGMENT_NAME table_name, ROUND(SUM(BYTES)/(1024*1024),2) data_size from DBA_SEGMENTS \n" +
                 "where INSTR(SEGMENT_TYPE,'TABLE') = 1 AND OWNER = ? group by SEGMENT_NAME";
//        List<TableTypeMapperDto.TableFirstPk> pkList =
//                query(getSchemaAllTablePkSql, new BeanListHandler<>(TableTypeMapperDto.TableFirstPk.class), schema);
        Map<String, Map<String, Object>> pkMap = query(getSchemaAllTablePkSql, new KeyedHandler<>(), schema);
//        List<TableTypeMapperDto.TableFirstFk> fkList =
//                query(getSchemaAllTableFkSql,new BeanListHandler<>(TableTypeMapperDto.TableFirstFk.class),schema);
        Map<String, Map<String, Object>> fkMap = query(getSchemaAllTableFkSql, new KeyedHandler<>(), schema);

//        List<TableTypeMapperDto.TableFirstCol> tableFirstColList =
//                query(getSchemaAllTableFistColSql,new BeanListHandler<>(TableTypeMapperDto.TableFirstCol.class),schema);
        Map<String, Map<String, Object>> firstColMap = query(getSchemaAllTableFistColSql, new KeyedHandler<>(), schema);

//        List<TableTypeMapperDto.TableDataSize> tableSizeMap =
//                query(getSchemaAllTableDataSizeSql,new BeanListHandler<>(TableTypeMapperDto.TableDataSize.class),schema);
        Map<String, Map<String, Object>> dataSizeMap = query(getSchemaAllTableDataSizeSql, new KeyedHandler<>(), schema);

        for (Map<String,Object> tableFirstCol:firstColMap.values()){
            TableTypeMapperDto tableTypeMapperDto = new TableTypeMapperDto();
            String tableName = tableFirstCol.get("table_name").toString();
            tableTypeMapperDto.setTableName(tableName);
            tableTypeMapperDto.setFirstColumn(tableFirstCol.get("column_name").toString());
            if (dataSizeMap.keySet().contains(tableName)){
                tableTypeMapperDto.setDataSize(new BigDecimal(dataSizeMap.get(tableName).get("data_size").toString()));
            }else {
                tableTypeMapperDto.setDataSize(new BigDecimal(0.00));
            }
            if (pkMap.keySet().contains(tableName)){
                tableTypeMapperDto.setPrimaryKey(pkMap.get(tableName).get("column_name").toString());
            }
            if (fkMap.keySet().contains(tableName)){
                tableTypeMapperDto.setForeignKey(fkMap.get(tableName).get("column_name").toString());
            }
            resultList.add(tableTypeMapperDto);
        }


        return resultList;
    }

    @Override
    public BigDecimal dataSize(String schema, String tableName) {
        BigDecimal dataSize = new BigDecimal(0.00);
        //查询表占用大小
        String dataSizeSql = "select ROUND(SUM(BYTES)/(1024*1024),2) data_size from DBA_SEGMENTS\n" +
                "where INSTR(SEGMENT_TYPE,'TABLE') = 1 AND OWNER = ? and SEGMENT_NAME = ?";
        //查询表大小
        dataSize = query(dataSizeSql, new ScalarHandler<BigDecimal>(), schema, tableName);
        if (dataSize == null) {
//            logger.info("dastasize = 0");
            dataSize = new BigDecimal(0.00);
        }
        return dataSize;
    }

    public String  getPartHighValue(String desc){
        //匹配TO_DATE(' 2013-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
        //括号里面的内容
        Pattern p1 = Pattern.compile("(?<=\\()[^\\)]+");
        Matcher m1 = p1.matcher(desc);
        List<String> list = Lists.newArrayList();
        List<String> result = Lists.newArrayList();
        while(m1.find()){
            String selectFromDualSql = "select to_date(" + m1.group() + ") from dual";
            Timestamp s1 = query(selectFromDualSql, new ScalarHandler<>());
            String s = s1.toString();
            desc = desc.replace("TO_DATE("+ m1.group()+")",s);
        }
        return desc;
    }

    public List<PartitionInfoDto> processPartition(String schema,String name, String partInfoSql,List<PartitionInfoDto> partitionInfos,
                                 Map<String,String> columnDto,Map<String, Object> properties,Map<String, Object> subProperties){
        partitionInfos = query(partInfoSql, new BeanListHandler<>(PartitionInfoDto.class), schema, name);
        String partitionBy = properties.get("PARTITIONBY").toString();
        String partitionColumnName = properties.get("PARTITIONCOLUMN").toString();
        List<String> partitionColumnList = Arrays.asList(partitionColumnName.split(","));
        String subPartionColumnName = null;
        String subPartitionBy = null;
        if (null != subProperties && !subProperties.isEmpty()) {
            subPartionColumnName = subProperties.get("SUBCOLUMN_NAME").toString();
            subPartitionBy = subProperties.get("SUBPARTITION_TYPE").toString();
        }
        String subPartInfoSql = "SELECT SUBPARTITION_NAME as subPartitionName,high_value as subPartHighValue" +
                " FROM dba_tab_subpartitions WHERE table_owner = ? AND table_name = ? AND partition_name = ? ORDER BY subpartition_position";
        if (partitionBy.equals("RANGE")) {
            for (PartitionInfoDto partitionInfoDto : partitionInfos){
                String partitionName = partitionInfoDto.getPartitionName();
                List<PartitionInfoDto.SubPartitionDto> subPartitionDtoList = Lists.newArrayList();
                String srcpartition = partitionInfoDto.getHighValue().toString();
                List<PartitionInfoDto.PartColumnDto> columnDtos = Lists.newArrayList();
                for (String col : partitionColumnList) {
                    String dataType = columnDto.get(col);
                    PartitionInfoDto.PartColumnDto dto = new PartitionInfoDto.PartColumnDto();
                    dto.setPartColumnName(col);
                    dto.setDataType(dataType);
                    columnDtos.add(dto);
                }
                //如果分区列有多列
                if (partitionColumnList.size() > 1) {
                    srcpartition = getPartHighValue(srcpartition);
                    StringBuilder tarDesc = new StringBuilder();
                    List<String> srcList = Arrays.asList(srcpartition.split(","));
                    for (int i = 0; i<srcList.size(); i++){
                        columnDtos.get(i).setHighValue(srcList.get(i));
                    }
                    partitionInfoDto.setPartColumnDtoList(columnDtos);
                    for (PartitionInfoDto.PartColumnDto partColumnDto : columnDtos) {
                        String dataType = partColumnDto.getDataType();
                        String srcpartitiondesc = partColumnDto.getHighValue().toString();
                        if (dataType.contains("TIMESTAMP")){
                            if (!srcpartitiondesc.equals("MAXVALUE")) {
                                String selectFromDualSql = "select " + srcpartitiondesc + " from dual";
                                List<Date> s1 = query(selectFromDualSql, new ColumnListHandler<Date>());
                                tarDesc.append(s1.get(0)).append(",");
                                partColumnDto.setValue(s1.get(0));
                            } else if (srcpartitiondesc.equals("MAXVALUE")) {
                                tarDesc.append(partColumnDto.getHighValue()).append(",");
                                partColumnDto.setValue(partColumnDto.getHighValue());
                            }
                        }
                        else {
                            tarDesc.append(partColumnDto.getHighValue()).append(",");
                            partColumnDto.setValue(partColumnDto.getHighValue());
                        }
                    }
                    String tarDesc1 = tarDesc.substring(0,tarDesc.length()-1);
                    partitionInfoDto.setValue(tarDesc1);
                    if (null != subProperties && !subProperties.isEmpty()) {
                        subPartitionDtoList = query(subPartInfoSql,new BeanListHandler<>(PartitionInfoDto.SubPartitionDto.class),schema,name,partitionName);
                        subPartitionDtoList = processSubPartition(subPartitionBy,columnDto,subPartionColumnName,subPartitionDtoList);
                    }
                    partitionInfoDto.setSubPartitionDtoList(subPartitionDtoList);
                } else if (partitionColumnList.size() == 1) {
                    if (columnDto.containsKey(partitionColumnName)){
                        columnDtos.get(0).setHighValue(srcpartition);
                        partitionInfoDto.setPartColumnDtoList(columnDtos);
                        PartitionInfoDto.PartColumnDto partColumnDto = partitionInfoDto.getPartColumnDtoList().get(0);
                        String dataType = columnDto.get(partColumnDto.getPartColumnName());
                        String srcpartitiondesc = partColumnDto.getHighValue().toString();
                        partColumnDto.setDataType(dataType);
                        if (dataType.equals("DATE") || dataType.contains("TIMESTAMP")){
                            if (!srcpartitiondesc.equals("MAXVALUE")) {
                                String selectFromDualSql = "select " + srcpartitiondesc + " from dual";
                                List<Date> s1 = query(selectFromDualSql, new ColumnListHandler<Date>());
                                partColumnDto.setValue(s1.get(0));
                            } else if (srcpartitiondesc.equals("MAXVALUE")) {
                                partColumnDto.setValue(partColumnDto.getHighValue());
                            }
                        } else {
                            partColumnDto.setValue(partColumnDto.getHighValue());
                        }
                    partitionInfoDto.getPartColumnDtoList().set(0,partColumnDto);
                    if (null != subProperties && !subProperties.isEmpty()) {
                        subPartitionDtoList = query(subPartInfoSql,new BeanListHandler<>(PartitionInfoDto.SubPartitionDto.class),schema,name,partitionName);
                        subPartitionDtoList = processSubPartition(subPartitionBy,columnDto,subPartionColumnName,subPartitionDtoList);
                    }
                    partitionInfoDto.setSubPartitionDtoList(subPartitionDtoList);
                  }
                }
            }
            if (partitionColumnList.size() == 1) {
                Collections.sort(partitionInfos, new Comparator<PartitionInfoDto>() {
                    @Override
                    public int compare(PartitionInfoDto o1, PartitionInfoDto o2) {
                        Object v1 = o1.getPartColumnDtoList().get(0).getValue();
                        Object v2 = o2.getPartColumnDtoList().get(0).getValue();
                        if (v1.toString().equals("MAXVALUE")) {
                            return 1;
                        } else if (v2.toString().equals("MAXVALUE")) {
                            return -1;
                        } else {
                            if (o1.getPartColumnDtoList().get(0).getDataType().contains("TIMESTAMP")) {
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                try {
                                    Date t11 = sdf.parse(v1.toString());
                                    Date t22 = sdf.parse(v2.toString());
                                    return t11.compareTo(t22);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    throw new RuntimeException(e);
                                }

                            } else {
                                try {
                                    BigDecimal v11 = new BigDecimal(v1.toString());
                                    BigDecimal v22 = new BigDecimal(v2.toString());
                                    return v11.compareTo(v22);
                                } catch (Exception e) {
                                    String c11 = v1.toString();
                                    String c22 = v2.toString();
                                    return c11.compareTo(c22);
                                }
                            }

                        }
                    }
                });
            }
        } else if (partitionBy.equals("LIST")){
            for (PartitionInfoDto partitionInfoDto:partitionInfos){
                List<PartitionInfoDto.SubPartitionDto> subPartitionDtoList = Lists.newArrayList();
                if (columnDto.containsKey(partitionColumnName)){
                    String dataType = columnDto.get(partitionColumnName);
                    String partitiondescr = partitionInfoDto.getHighValue().toString();
                    partitionInfoDto.setDataType(dataType);

                    if (dataType.equals("DATE")){
                        List<String> dateList = Lists.newArrayList();
                        //匹配（）小括号内容
                        Pattern pattern = Pattern.compile("(?<=\\()[^\\)]+");
                        Matcher matcher = pattern.matcher(partitiondescr);
                        while(matcher.find()){
                            dateList.add(matcher.group());
                        }
                        List<String> srcList = Lists.newArrayList();
                        for (String datei: dateList) {
                            if (!datei.equalsIgnoreCase("DEFAULT")) {
                                String selectFromDualSql = "select to_date(" + datei + ") from dual";
                                List<Timestamp> s1 = query(selectFromDualSql, new ColumnListHandler<>());
                                if (CollectionUtils.isNotEmpty(s1)) {
                                    srcList.add(s1.get(0).toString());
                                }
                            } else {
                                srcList.add("DEFAULT");
                            }
                        }
                        String desc = String.join(",",srcList);
                        partitionInfoDto.setValue(desc);
                    } else if (dataType.contains("TIMESTAMP")) {
                        List<String> dateList = Arrays.asList(StringUtils.split(partitiondescr,","));
                        List<String> srcList = Lists.newArrayList();
                        for (String datei: dateList) {
                            if (!datei.equalsIgnoreCase("DEFAULT")){
                                String selectFromDualSql = "select " + datei + "from dual";
                                List<Object> s1 = query(selectFromDualSql, new ColumnListHandler<>());
                                if (CollectionUtils.isNotEmpty(s1)) {
                                    srcList.add(s1.get(0).toString());
                                }
                            } else {
                                srcList.add("DEFAULT");
                            }
                        }
                        String desc = String.join(",",srcList);
                        partitionInfoDto.setValue(desc);
                    }
                    else {
                        partitionInfoDto.setValue(partitionInfoDto.getHighValue());
                    }
                }
                if (null != subProperties && !subProperties.isEmpty()) {
                    subPartitionDtoList = query(subPartInfoSql, new BeanListHandler<>(PartitionInfoDto.SubPartitionDto.class), schema, name, partitionInfoDto.getPartitionName());
                    subPartitionDtoList = processSubPartition(subPartitionBy,columnDto,subPartionColumnName,subPartitionDtoList);
                }
                partitionInfoDto.setSubPartitionDtoList(subPartitionDtoList);
            }
        } else if (partitionBy.equals("HASH")){
            for (PartitionInfoDto partitionInfoDto : partitionInfos){
                List<PartitionInfoDto.SubPartitionDto> subPartitionDtoList = Lists.newArrayList();
                List<PartitionInfoDto.PartColumnDto> columnDtos = Lists.newArrayList();
                for (String col : partitionColumnList) {
                    String dataType = columnDto.get(col);
                    PartitionInfoDto.PartColumnDto dto = new PartitionInfoDto.PartColumnDto();
                    dto.setPartColumnName(col);
                    dto.setDataType(dataType);
                    columnDtos.add(dto);
                }
                for (PartitionInfoDto.PartColumnDto partColumnDto : columnDtos) {
                    if (columnDto.containsKey(partColumnDto.getPartColumnName())){
                        String dataType = columnDto.get(partColumnDto.getPartColumnName());
                        partColumnDto.setDataType(dataType);
                    }
                }
                if (null != subProperties && !subProperties.isEmpty()) {
                    subPartitionDtoList = query(subPartInfoSql, new BeanListHandler<>(PartitionInfoDto.SubPartitionDto.class), schema, name, partitionInfoDto.getPartitionName());
                    subPartitionDtoList = processSubPartition(subPartitionBy,columnDto,subPartionColumnName,subPartitionDtoList);
                }
                partitionInfoDto.setPartColumnDtoList(columnDtos);
                partitionInfoDto.setSubPartitionDtoList(subPartitionDtoList);
            }
        }
//        properties.put("PARTITIONED","YES");
        return partitionInfos;
    }

    public List<PartitionInfoDto.SubPartitionDto> processSubPartition(String subPartitionBy, Map<String,String> columnDto,
                                                                      String subPartionColumnName, List<PartitionInfoDto.SubPartitionDto> subPartitionDtoList) {
        if (subPartitionBy.equals("RANGE")) {
            for (PartitionInfoDto.SubPartitionDto subPartitionDto:subPartitionDtoList) {
                if (columnDto.containsKey(subPartionColumnName)){
                    String subColumnDataType = columnDto.get(subPartionColumnName);
                    String subSrcpartitiondesc = subPartitionDto.getSubPartHighValue().toString();
                    if (subColumnDataType.equals("DATE") || subColumnDataType.contains("TIMESTAMP")){
                        if (!subSrcpartitiondesc.equals("MAXVALUE")) {
                            String selectFromDualSql = "select " + subSrcpartitiondesc + " from dual";
                            List<Date> s1 = query(selectFromDualSql, new ColumnListHandler<Date>());
                            subPartitionDto.setSubValue(s1.get(0));
                        } else if (subSrcpartitiondesc.equals("MAXVALUE")) {
                            subPartitionDto.setSubValue(subPartitionDto.getSubPartHighValue());
                        }
                    }
                    else {
                        subPartitionDto.setSubValue(subPartitionDto.getSubPartHighValue());
                    }
                    subPartitionDto.setSubDataType(subColumnDataType);
                }
                subPartitionDto.setSubPartitionBy(subPartitionBy);
//                            subPartitionDtoList.add(subPartitionDto);
            }
//            List<String> subPartitionColumnList = Arrays.asList(subPartionColumnName.split(","));
//            if (subPartitionColumnList.size() == 1) {
//                Collections.sort(subPartitionDtoList, new Comparator<PartitionInfoDto.SubPartitionDto>() {
//                    @Override
//                    public int compare(PartitionInfoDto.SubPartitionDto o1, PartitionInfoDto.SubPartitionDto o2) {
//                        Object v1 = o1.getSubPartHighValue();
//                        Object v2 = o2.getSubPartHighValue();
//                        if (v1.toString().equals("MAXVALUE")) {
//                            return 1;
//                        } else if (v2.toString().equals("MAXVALUE")) {
//                            return -1;
//                        } else {
//                            if (o1.getSubDataType().contains("TIMESTAMP")) {
//                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                                try {
//                                    Date t11 = sdf.parse(v1.toString());
//                                    Date t22 = sdf.parse(v2.toString());
//                                    return t11.compareTo(t22);
//                                } catch (Exception e) {
//                                    e.printStackTrace();
//                                    throw new RuntimeException(e);
//                                }
//
//                            } else {
//                                try {
//                                    BigDecimal v11 = new BigDecimal(v1.toString());
//                                    BigDecimal v22 = new BigDecimal(v2.toString());
//                                    return v11.compareTo(v22);
//                                } catch (Exception e) {
//                                    String c11 = v1.toString();
//                                    String c22 = v2.toString();
//                                    return c11.compareTo(c22);
//                                }
//                            }
//
//                        }
//                    }
//                });
//            }
        } else if (subPartitionBy.equals("LIST")) {
            for (PartitionInfoDto.SubPartitionDto subPartitionDto : subPartitionDtoList) {
                String subDataType = columnDto.get(subPartionColumnName);
                String partitiondescr = subPartitionDto.getSubPartHighValue().toString();
                subPartitionDto.setSubDataType(subDataType);
                if (subDataType.equals("DATE") || subDataType.contains("TIMESTAMP")){
                    List<String> dateList = Lists.newArrayList();
                    Pattern pattern = Pattern.compile("(?<=\\()[^\\)]+");
                    Matcher matcher = pattern.matcher(partitiondescr);
                    while(matcher.find()){
                        dateList.add(matcher.group());
                    }
                    List<String> srcList = Lists.newArrayList();
                    for (String datei: dateList) {
                        String selectFromDualSql = "select to_date(" + datei + ") from dual";
                        List<Timestamp> s1 = query(selectFromDualSql, new ColumnListHandler<>());
                        if (CollectionUtils.isNotEmpty(s1)) {
                            srcList.add(s1.get(0).toString());
                        }
                    }
                    String desc = String.join(",",srcList);
                    subPartitionDto.setSubValue(desc);
                }
                else {
                    subPartitionDto.setSubValue(subPartitionDto.getSubPartHighValue());
                }
                subPartitionDto.setSubPartitionBy(subPartitionBy);
//                        subPartitionDtoList.add(subPartitionDto);
            }
        } else if (subPartitionBy.contains("HASH")) {
            for (PartitionInfoDto.SubPartitionDto subPartitionDto : subPartitionDtoList) {
                if (columnDto.containsKey(subPartionColumnName)){
                    String dataType = columnDto.get(subPartionColumnName);
                    subPartitionDto.setSubDataType(dataType);
                }
                subPartitionDto.setSubPartitionBy(subPartitionBy);
//                        subPartitionDtoList.add(subPartitionDto);
            }
        }
        return subPartitionDtoList;
    }
}
